﻿using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinMqttClient
{
    public partial class FrmMqttClientMain : Form
    {
        private MqttClient mqttClient = null;
        private bool isCancelSend = false;

        public FrmMqttClientMain()
        {
            InitializeComponent();
           
        }




        private async Task ConnectMqttServerAsync()
        {
            if (mqttClient == null)
            {
                mqttClient = new MqttFactory().CreateMqttClient() as MqttClient;
                mqttClient.ApplicationMessageReceived += MqttClient_ApplicationMessageReceived;
                mqttClient.Connected += MqttClient_Connected;
                mqttClient.Disconnected += MqttClient_Disconnected;
                
            }

            try
            {

                var options = new MqttClientOptions
                {
                    ClientId = Guid.NewGuid().ToString(),
                    CleanSession = true,
                    //UserName = "u001",
                    //Password = "p001",
                    ChannelOptions = new MqttClientTcpOptions
                    {
                        //Server = "localhost",
                        Server = txtServerIP.Text,//"192.168.1.196",// "192.168.1.196",
                        Port = Convert.ToInt32(txtPort.Text),//1883,//Convert.ToInt32(txtb_serverport.Text.Trim()),
                        BufferSize = 20 * 400,
                    },
                    //ChannelOptions = new MqttClientWebSocketOptions
                    //{
                    //    Uri = "ws://localhost:59690/mqtt"
                    //}
                };

                await mqttClient.ConnectAsync(options);
            }
            catch (Exception ex)
            {
                Invoke((new Action(() =>
                {
                    txtReceiveMessage.AppendText($"连接到MQTT服务器失败！" + Environment.NewLine + ex.Message + Environment.NewLine);
                })));
            }
        }

        private void MqttClient_Connected(object sender, EventArgs e)
        {
            Invoke((new Action(() =>
            {
                txtReceiveMessage.AppendText("已连接到MQTT服务器！" + Environment.NewLine);
            })));
        }

        private void MqttClient_Disconnected(object sender, EventArgs e)
        {
            showMsg("已断开MQTT连接！");
            Invoke((new Action(() =>
            {
                btnSubscribe.Enabled = true;
                txtSubTopic.Enabled = true;
            })));
        }

        private void MqttClient_ApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        {
            Invoke((new Action(() =>
            {
                txtReceiveMessage.AppendText($">> {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}{Environment.NewLine}");
                
            })));
        }

        private void SubTopic(String topic)
        {
            List<TopicFilter> list = new List<TopicFilter>();
            string[] topics = topic.Split(new char[] { ',' });
            foreach (string str in topics)
            {
                list.Add(new TopicFilter(str, MqttQualityOfServiceLevel.AtMostOnce));
            }
            mqttClient.SubscribeAsync(list);

            showMsg($"已订阅[{topic}]主题");
            txtSubTopic.Enabled = false;
            btnSubscribe.Enabled = false;
        }

        private void BtnSubscribe_ClickAsync(object sender, EventArgs e)
        {
            string topic = txtSubTopic.Text.Trim();

            if (string.IsNullOrEmpty(topic))
            {
                MessageBox.Show("订阅主题不能为空！");
                return;
            }

            if (!mqttClient.IsConnected)
            {
                MessageBox.Show("MQTT客户端尚未连接！");
                return;
            }

            int length = 1;
            string strCount = txtSubCount.Text.Trim();
            if (!"".Equals(strCount))
            {
                length = Convert.ToInt32(txtSubCount.Text);
            }

            for (int i = 0; i < length; i++)
            {
                SubTopic(topic);
            }
        }

        

        private void BtnPublish_Click(object sender, EventArgs e)
        {
            isCancelSend = false;
            string topic = txtPubTopic.Text.Trim();

            if (string.IsNullOrEmpty(topic))
            {
                MessageBox.Show("发布主题不能为空！");
                return;
            }
            int length = 1;
            string strCount = txtSendCount.Text.Trim();
            if (!"".Equals(strCount))
            {
                length = Convert.ToInt32(txtSendCount.Text);
            }
            string inputString = txtSendMessage.Text.Trim();
            var appMsg = new MqttApplicationMessage();// (topic, Encoding.UTF8.GetBytes(inputString), MqttQualityOfServiceLevel.AtMostOnce, false);
            appMsg.Topic = topic;
            appMsg.Payload = Encoding.UTF8.GetBytes(inputString);
            appMsg.QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
            appMsg.Retain = false;
            for (int i = 0; i < length; i++)
            {
                Application.DoEvents();
                if (isCancelSend)
                {
                    showMsg("用户取消了发送.");
                    break;
                }
                mqttClient.PublishAsync(appMsg);
                if((i + 1) % 1000 == 0)
                {
                    showMsg(string.Format("发送了{0}", i + 1));
                }
            }
           
        }

        private void btnConnectServer_Click(object sender, EventArgs e)
        {
            Task.Run(async () => { await ConnectMqttServerAsync(); });
        }

        private void btnCloseServer_Click(object sender, EventArgs e)
        {
            if(mqttClient == null || !mqttClient.IsConnected) { return; }
            mqttClient.DisconnectAsync();
        }

        private void btnUnSubscribe_Click(object sender, EventArgs e)
        {
            string topic = txtSubTopic.Text.Trim();

            if (string.IsNullOrEmpty(topic))
            {
                MessageBox.Show("订阅主题不能为空！");
                return;
            }
            if (!mqttClient.IsConnected)
            {
                MessageBox.Show("MQTT客户端尚未连接！");
                return;
            }

            string[] topics = topic.Split(new char[]{','});
            List<string> list = new List<string>();
            foreach(string str in topics)
            {
                list.Add(str);
            }
            mqttClient.UnsubscribeAsync(list);

            showMsg($"取消订阅[{topic}]主题");
            txtSubTopic.Enabled = true;
            btnSubscribe.Enabled = true;
        }

        private void txtSendMessage_TextChanged(object sender, EventArgs e)
        {

        }

        private void showMsg(string msg)
        {
            Invoke((new Action(() =>
            {
                // if(txtReceiveMessage.Lines.Length > 2000)
                //{
                //    for (int i = 0; i < 1000; i++)
                //    {
                //        txtReceiveMessage.Lines.de
                //    } 
                //}
                int rows = 100;
                if (txtReceiveMessage.Lines.Length > rows)
                {
                    string[] sLines = txtReceiveMessage.Lines;
                    string[] sNewLines = new string[sLines.Length - rows];

                    Array.Copy(sLines, rows, sNewLines, 0, sNewLines.Length);
                    txtReceiveMessage.Lines = sNewLines;
                }
                txtReceiveMessage.AppendText(msg + Environment.NewLine);
            })));
        }

        private void btnSendCancel_Click(object sender, EventArgs e)
        {
            isCancelSend = false;
        }

        private void txtReceiveMessage_TextChanged(object sender, EventArgs e)
        {
            txtReceiveMessage.SelectionStart = txtReceiveMessage.Text.Length;
            txtReceiveMessage.ScrollToCaret();
        }
    }
}
